from typing import TypeVar, overload, List, Dict

from pydantic import BaseModel

from app.db.base_class import Base


class Copier:
    _T = TypeVar('T', bound=Base)
    _PT = TypeVar('PT', bound=BaseModel)

    @staticmethod
    @overload
    def copy(source: dict, target: _T) -> _T:
        """
        字典 转 sqlalchemy model
        """
        ...

    @staticmethod
    @overload
    def copy(source: dict, target: _PT) -> _PT:
        """
        字典 转 pydantic model
        """
        ...

    @staticmethod
    @overload
    def copy(source: _T, target: _PT) -> _PT:
        """
        sqlalchemy 转  pydantic model
        """
        ...

    @staticmethod
    @overload
    def copy(source: _PT, target: _T) -> _T:
        """
        pydantic model 转 sqlalchemy
        """
        ...

    @staticmethod
    @overload
    def copyList(source: List[dict], target: _T) -> _T:
        """
        字典 转 sqlalchemy model
        """
        ...

    @staticmethod
    @overload
    def copyList(source: List[dict], target: _PT) -> _PT:
        """
        字典 转 pydantic model
        """
        ...

    @staticmethod
    @overload
    def copyList(source: List[_T], target: _PT) -> _PT:
        """
        sqlalchemy 转  pydantic model
        """
        ...

    @staticmethod
    @overload
    def copyList(source: List[_PT], target: _T) -> _T:
        """
        pydantic model 转 sqlalchemy
        """
        ...

    @staticmethod
    def copy(source, target):
        if not source:
            return None
        # 字典转model
        if isinstance(source, dict):
            return target(**source)
        # 字典转sqlalchemy
        if isinstance(source, Base):
            return target(**source)
        # sqlalchemy转model
        if isinstance(source, Base):
            return target.from_rom(source)
        # model转model
        if isinstance(source, BaseModel):
            return target(**source.dict())
        # if isinstance()

    @staticmethod
    def copyList(source, target):
        if not source:
            return None
        if len(source) == 0:
            return []
        # 获取第一个元素
        first = source[0]
        result = [Copier.copy(el, target) for el in source]
        return result

